import GameConfig from "../GameConfig";
import DebugExt from "../NRLib/base/DebugExt";
import UILangData, { SimpleLangData } from "../NRLib/base/UILangData";


/** 退出游戏操作的参数接口 */
interface IExitParam {
    /** 提示文本，有提示文本，或游戏进行时退出，弹出确认框 */
    tips?: string,
    /** 弹出框按钮样式 */
    btnType?: yy.MBBtnType
}

// 添加全局事件监听器
window.addEventListener('message', (event) => {
    if (event.data === 'MoneyChanged') {
        console.log("MoneyChanged 事件触发，通知货币已更新！");
        yy.myself.updateThirdMoney(0, true);
        console.log("客户端请求更新货币信息！");
    }
});

/** 静态方法类，处理 ZEGO 事件用 */
export default class ZegoEvents {

    // 消息框多语言信息
    private static get langData(): UILangData {
        if (!this._langData) {
            this._langData = new UILangData(GameConfig.langList, 'en');
            const json: SimpleLangData = {
                "QuitGameTips": {
                    "en": "Are you sure you want to exit the game? Exiting the game will be considered as surrender and deduct this round's in-game currency.",
                    "zh": "确定要退出游戏吗？退出游戏会被视为投降，并扣除本轮游戏币。",
                    "zhf": "確定要退出遊戲嗎？退出遊戲會被視為投降，並扣除本輪遊戲幣。",
                    "jp": "ゲームを終了しますか？ゲームを終了すると降参と見なされ、今回のゲーム内通貨が差し引かれます。",
                    "id": "Apakah Anda yakin ingin keluar dari permainan? Keluar dari permainan akan dianggap sebagai menyerah dan akan mengurangkan mata uang dalam permainan untuk putaran ini.",
                    "hi": "क्या आप निश्चित हैं कि आप खेल से बाहर जाना चाहते हैं? खेल से बाहर निकलना सरेंडर के रूप में माना जाएगा और इस राउंड के खेल में उपयोग होने वाले मुद्रा को कटा देगा।",
                    "pt": "Tem certeza de que deseja sair do jogo? Sair do jogo será considerado como rendição e deduzirá a moeda in-game desta rodada.",
                    "es": "¿Estás seguro de que quieres salir del juego? Salir del juego se considerará como rendición y descontará la moneda in-game de esta ronda.",
                    "ru": "Вы уверены, что хотите выйти из игры? Выход из игры будет считаться сдачей и учтет валюту внутри игры за этот раунд.",
                    "ar": "هل أنت متأكد أنك تريد الخروج من اللعبة؟ الخروج من اللعبة سيعتبر استسلامًا وسيتم خصم عملة اللعبة لهذا الجولة.",
                    "ms": "Adakah anda pasti mahu keluar dari permainan? Keluar dari permainan akan dianggap sebagai menyerah dan akan mengurangkan mata wang dalam permainan pada pusingan ini."
                },
                "UserInGame": {
                    "en": "The current character is in another game and cannot participate in multiple games simultaneously!",
                    "zh": "当前角色处于其他游戏中, 无法同时进行多场游戏！",
                    "zhf": "當前角色處於其他遊戲中，無法同時參加多場遊戲！",
                    "jp": "現在のキャラクターは別のゲームに参加しており、同時に複数のゲームに参加することはできません。",
                    "id": "Karakter saat ini sedang berada dalam permainan lain dan tidak dapat berpartisipasi dalam beberapa permainan sekaligus!",
                    "hi": "वर्तमान पात्रिक एक अन्य खेल में है और एक साथ कई खेलों में भाग नहीं ले सकता है!",
                    "pt": "O personagem atual está em outro jogo e não pode participar em vários jogos simultaneamente!",
                    "es": "El personaje actual está en otro juego y no puede participar en múltiples juegos simultáneamente!",
                    "ru": "Текущий персонаж находится в другой игре и не может участвовать в нескольких играх одновременно!",
                    "ar": "الشخصية الحالية في لعبة أخرى ولا يمكنها المشاركة في أكثر من لعبة في نفس الوقت!",
                    "ms": "Karakter semasa berada dalam permainan lain dan tidak dapat menyertai beberapa permainan pada masa yang sama!"
                },
                "NoRoomTips": {
                    "en": "There are currently no available game rooms to join!",
                    "zh": "暂无可进入的游戏房间！",
                    "zhf": "目前沒有可加入的遊戲房間！",
                    "jp": "現在、参加可能なゲームルームはありません。",
                    "id": "Saat ini tidak ada ruang permainan yang tersedia untuk bergabung!",
                    "hi": "वर्तमान में कोई उपलब्ध खेल कक्ष नहीं हैं!",
                    "pt": "Atualmente, não há salas de jogo disponíveis para entrar!",
                    "es": "Actualmente, no hay salas de juego disponibles para unirse!",
                    "ru": "В данный момент нет доступных игровых комнат для присоединения!",
                    "ar": "لا توجد غرف ألعاب متاحة حاليًا للانضمام إليها!",
                    "ms": "Tiada bilik permainan yang tersedia untuk disertai pada masa ini!"
                },
                "almTips": {
                    "en": "Insufficient coins. To ensure a seamless experience, please recharge in a timely manner.",
                    "zh": "金币不足，为了不影响您的体验请及时充值。",
                    "zhf": "金幣不足，為了不影響您的體驗請及時充值。",
                    "jp": "コインが不足しています。スムーズな体験を確保するために、適時にチャージしてください。",
                    "id": "Kekurangan koin. Untuk memastikan pengalaman yang lancar, harap isi ulang dengan tepat waktu.",
                    "hi": "कम सिक्के। एक सुगम अनुभव सुनिश्चित करने के लिए, कृपया समय पर रिचार्ज करें।",
                    "pt": "Moedas insuficientes. Para garantir uma experiência sem problemas, recarregue a tempo.",
                    "es": "Monedas insuficientes. Para asegurar una experiencia sin problemas, recargue a tiempo.",
                    "ru": "Недостаточно монет. Чтобы обеспечить бесперебойный опыт, пополните свой счет вовремя.",
                    "ar": "نقص العملات. لضمان تجربة سلسة، يُرجى إعادة الشحن في الوقت المناسب.",
                    "ms": "Kekurangan syiling. Untuk memastikan pengalaman yang lancar, sila tambah nilai pada masa yang sesuai."
                }
            };
            this._langData.setJsonLangData(json);
        }
        return this._langData;
    }
    private static _langData: UILangData = null;
    // 获取多语言文本
    static getString(key: string, ...param: Array<string | number>): string {
        return this.langData.getString(key, ...param);
    }

    /** 进入游戏场景通用接口 */
    static enterGame() {
        const resumeInfo = yy.lobby.getResumeGameInfo();
        const inSubGame: boolean = "MapMasterID" in GameConfig && !!resumeInfo && GameConfig.MapMasterID == resumeInfo.gameID;
        if (resumeInfo && resumeInfo.roomFlag && !inSubGame) {
            if (resumeInfo.gameID != GameConfig.GameID) {
                this.errorQuit(this.getString("UserInGame"));
            }
            else {
                this.doEnterGame(resumeInfo.roomFlag);
                DebugExt.log("玩家：", yy.myself.userID, "恢复场景, 游戏ID：", resumeInfo.gameID, " 房间号：", resumeInfo.roomFlag);
            }
        }
        else if (GameConfig.isZEGO && !resumeInfo) {
            const gameinfo = yy.getGameInfo(GameConfig.GameID);
            let evt = new yy.event.lobby.FindAutoJoinRoom();
            evt.gameInfo = gameinfo;
            yy.event.emit(yy.event.lobby.FindAutoJoinRoom, evt);
            if (evt.result == 0) {
                this.doEnterGame(evt.roomFlag);
                DebugExt.log("玩家：", yy.myself.userID, "正常登录Zego, 游戏ID：", gameinfo.gameID, " 房间号：", evt.roomFlag);
            }
            else {
                this.errorQuit(this.getString("NoRoomTips"));
            }
        }
        else {
            // 非zego游戏进房，本地选择一个货币合适的房间即可
            const flag = this.getUsefulRoomFlag(GameConfig.GameID);
            if (flag > 0) {
                if (inSubGame && ZegoEvents.inGaming) {
                    yy.room.reqExitRoom();
                }
                this.doEnterGame(flag);
                DebugExt.log("玩家：", yy.myself.userID, "正常登录, 游戏ID：", GameConfig.GameID, " 房间号：", flag);
            }
            else {
                DebugExt.warn("进房失败：", flag == 0 ? '钱不够！' : '没房间！');
                this.errorQuit(this.getString("NoRoomTips"));
            }
        }
    }

    /** 通知上层事件--离开游戏 */
    static exitGame(p?: IExitParam) {
        const hasTips: boolean = !!p && !!p.tips && p.tips.trim().length > 0;
        if (hasTips) {
            // // 游戏进行中退出，需要弹出确认框
            // const tips: string = hasTips ? p.tips : this.getString("QuitGameTips");
            const btnType: yy.MBBtnType = (!p || p.btnType == undefined || p.btnType == null) ? yy.MBBtnType.YesNo : p.btnType;
            this.errorQuit(p.tips, btnType);
        }
        else {
            this.doExitGame();
        }
    }

    /** 添加网页充值监听事件 */
    private static addXingGuangRechargePageShowListener() {
        console.log("添加 onPageShow 事件监听！");
        // @ts-ignore
        window.onPageShow = () => {
            console.log("onPageShow 事件触发！");
            yy.myself.updateThirdMoney(0, true);
            console.log("客户端请求更新货币信息！");
        };
    }

    /** 调用平台充值 */
    static recharge(zegoTips: boolean = false, source: string = "") {
        const pkgid = yy.lobby.getPackageID();
        const urlParam = yy.gf.getURLParam("", true);

        if (GameConfig.isZEGO) {
            if (zegoTips)
                yy.ui.messageBox(this.getString("almTips"), () => {
                    this.zegoEvent("MoneyNotEnough");
                });
            else
                this.zegoEvent("MoneyNotEnough");
            return true;
        }
        else if (pkgid == "xingguang") {
            // xingguang 渠道，约定特殊处理
            console.log(pkgid, " 渠道, 货币不足，拉起指定url!");
            this.addXingGuangRechargePageShowListener();

            const url = urlParam.exchange_url;
            if (cc.sys.os == cc.sys.OS_ANDROID) {
                let gBridge = (window as any).gBridge;
                if (gBridge) {
                    gBridge.toUrl(url);
                    return true;
                }
            }
            else {
                let webkit = (window as any).webkit;
                if (webkit) {
                    if (webkit.messageHandlers) {
                        if (webkit.messageHandlers.toUrl) {
                            webkit.messageHandlers.toUrl.postMessage(url);
                            return true;
                        }
                    }
                }
            }

            console.warn("渠道: xingguang " + cc.sys.os + "平台 未支持约定的充值API接口！");
            return false;
        }
        else if (pkgid == "guochao") {
            // 郑州国超渠道，约定特殊处理
            const params = {
                gameId: GameConfig.GameID,
                type: source == "ButtonExchange" ? 1 : 0
            };
            const paramsStr = JSON.stringify(params);
            console.log(pkgid, " 渠道, 货币不足，传递指定消息gameRecharge, params=", paramsStr);
            window.parent.postMessage({ type: 'gameRecharge', params: paramsStr }, '*');
            return true;
        }
        else if (yy.thirdPlatform.getPlatformName()) {
            // 【框架通用SDK处理方案】
            yy.thirdPlatform.reqRecharge();
            return true;
        }
        else if (urlParam && urlParam.exchange_url) {
            // exchange_url 改为通用方案
            console.debug(pkgid, "渠道, 触发货币不足充值事件，exchange_url=", urlParam.exchange_url);
            window.open(urlParam.exchange_url, '_blank');
            return true;
        }
        else {
            yy.ui.messageBox(this.getString("almTips"));
            console.log((!pkgid ? "无" : pkgid), " 渠道, 触发货币不足充值事件，暂无充值接口！！！");
        }
    }

    /** 加载游戏成功失败通知 */
    static loadGame(suc: boolean) {
        this.zegoEvent(suc ? "LoadGameComplete" : "LoadGameFailed");
    }

    /** 大局结算框--关闭 */
    static settleGameEnd() {
        this.zegoEvent("SettleClose");
    }

    /** 大局结算框--再来一局 */
    static settlePlayAgain() {
        this.zegoEvent("SettlePlayAgin");
    }

    /**
     * ZEGO音效托管配置
     */
    static initAudioConfig(): boolean {
        if (!GameConfig.isZEGO) {
            yy.setting.musicVolume = 1;
            yy.setting.effectVolume = 1;
            return false;
        }
        let evt2 = new yy.event.lobby.CommonEvent();
        evt2.type = "IsExternPlayGameAudio";
        yy.event.emit(yy.event.lobby.CommonEvent, evt2);
        // 是否使用预制音源
        const isExternPlayAudio: boolean = evt2.data;
        DebugExt.log("音效控制权：", isExternPlayAudio ? "ZEGO" : "游戏本身");
        return isExternPlayAudio;
    }
    /**
     * 托管游戏音效资源
     * @param clips 音效资源列表
     */
    static uploadClips(clips: yy.IAudioClip[]) {
        CC_PREVIEW && clips.forEach(iclip => DebugExt.log("托管游戏音效：", iclip.clip.name, " loop:", !iclip.loop ? "False" : "True"));
        let evt3 = new yy.event.lobby.CommonEvent();
        evt3.type = "ExternPreSetAudioClip";
        evt3.data = clips;
        yy.event.emit(yy.event.lobby.CommonEvent, evt3);
    }

    /** 通知第三方播放指定音效 */
    static playAudio(clip: cc.AudioClip, volume: number) {
        DebugExt.log("通知ZEGO播放音效：", clip.name);
        const data: yy.IAudioClip = { clip, volume };
        this.zegoEvent("ExternPlayAudioClip", data);
    }

    /** 通知第三方关闭指定音效 */
    static stopAudio(clip: cc.AudioClip, volume: number) {
        DebugExt.log("通知ZEGO关闭音效：", clip.name);
        const data: yy.IAudioClip = { clip, volume };
        this.zegoEvent("ExternStopAudioClip", data);
    }

    /** 改变指定音源音量 */
    static changeVolume(clip: cc.AudioClip, volume: number) {
        DebugExt.log("改变ZEGO音源音量：", clip.name);
        const data: yy.IAudioClip = { clip, volume };
        this.zegoEvent("ExternSetAudioVolume", data);
    }

    /** 更新游戏状态--playing */
    static gamePhasePlaying() {
        DebugExt.debug("更新游戏状态--playing; isPlaying：", this.isPlaying);
        this.isPlaying = true;
        this.zegoEvent("GamePhasePlaying");
    }
    /** 更新游戏状态--playEnd */
    static gamePhasePlayEnd() {
        DebugExt.debug("更新游戏状态--playEnd; isPlaying：", this.isPlaying);
        if (this.isPlaying) {
            this.isPlaying = false;
            this.zegoEvent("GamePhasePlayEnd");
        }
    }
    private static isPlaying: boolean = false;

    /** 检查并启用超时判断 */
    static checkTimeout() {
        this.cancelTimeout();
        const evnCfg = yy.thirdPlatform.getEnvConfigs();
        if (GameConfig.isZEGO && evnCfg.zego && evnCfg.zego.gameMode == 1) {
            const cfg = yy.thirdPlatform.getEnvConfigs().zego.gameConfig.specificConfig;
            if (!cfg) return;
            let timeOut = 0;
            if (cfg.gameTimeout !== undefined)
                timeOut = Number(cfg.gameTimeout) || 0;
            if (timeOut < 1) return;
            // 放宽冗余时间3秒
            if (timeOut >= 5000)
                timeOut += 300;
            else
                timeOut = (timeOut + 3) * 1000;
            DebugExt.log("当前主播场，且启用超时配置; gameTimeout=", cfg.gameTimeout);
            this._timerID = window.setTimeout(() => {
                yy.thirdPlatform.onClientMatchTableTimeout();
                DebugExt.log("客户端发送超时判断！");
            }, timeOut);
        }
    }
    private static _timerID: number = -1;

    /** 移除超时判断定时器 */
    static cancelTimeout() {
        if (this._timerID >= 0) {
            clearTimeout(this._timerID);
            this._timerID = -1;
        }
    }

    /** 是否显示货币符号--默认显示 */
    static isShowMoneyIcon(): boolean {
        const evnCfg = yy.thirdPlatform.getEnvConfigs();
        if (GameConfig.isZEGO && evnCfg && evnCfg.zego) {
            if (evnCfg.zego.gameConfig && evnCfg.zego.gameConfig.specificConfig) {
                const moneyMode = evnCfg.zego.gameConfig.specificConfig["moneyMode"];
                if (moneyMode !== undefined)
                    return moneyMode != "0";
            }
        }
        return true;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////

    // 通用 ZEGO 事件
    private static zegoEvent(type: yy.event.lobby.ICommenEventType, data?: any) {
        let evt2 = new yy.event.lobby.CommonEvent();
        evt2.type = type;
        evt2.data = data;
        yy.event.emit(yy.event.lobby.CommonEvent, evt2);
    }

    // 异常退出告知
    private static errorQuit(tips: string, btnType: yy.MBBtnType = yy.MBBtnType.Yes) {
        yy.ui.messageBox(tips, (btn: yy.MBBtn) => {
            if (btn == yy.MBBtn.Yes || btnType == yy.MBBtnType.Yes)
                this.doExitGame();
        }, this, btnType);
    }

    // 切换游戏场景，并进入游戏房间
    private static doEnterGame(flag: number) {
        cc.director.loadScene(this.gameSceneName, () => {
            this.doEnterRoom(flag);
            yy.pv.gameRunHelper.setRunningSceneType(yy.SceneType.Game);
        });
    }

    public static doEnterRoom(flag: number) {
        const gameinfo = yy.getGameInfo(GameConfig.GameID);
        // 特殊处理token房登录方式
        if (GameConfig.isTokenRoom)
            gameinfo.reqEnterRoomByToken();
        else
            gameinfo.reqEnterRoomByFlag(flag);
    }

    // 退出游戏
    private static doExitGame(): boolean {
        const pkgid = yy.lobby.getPackageID();
        if (this.inGaming && pkgid != "guochao")
            yy.room.reqExitRoom();

        const urlParam = yy.gf.getURLParam("", true);

        if (GameConfig.isZEGO) {
            yy.event.emit(yy.event.lobby.ExitGame, new yy.event.lobby.ExitGame());
            return true;
        }
        else if (pkgid == "aig_half") {
            // aig渠道，半屏模式需要特殊处理
            window.history.back();
            return true;
        }
        else if (pkgid == "xingguang") {
            if (cc.sys.os == cc.sys.OS_ANDROID) {
                let recharge = (window as any).recharge;
                if (recharge) {
                    recharge.goBack();
                    return true;
                }
            }
            else {
                let webkit = (window as any).webkit;
                if (webkit) {
                    if (webkit.messageHandlers) {
                        if (webkit.messageHandlers.closeWeb) {
                            webkit.messageHandlers.closeWeb.postMessage(null);
                            return true;
                        }
                    }
                }
            }
            console.warn("渠道: xingguang " + cc.sys.os + "平台 未支持约定的退出API接口！");
        }
        else if (pkgid == "guochao") {
            // 郑州国超渠道，约定特殊处理
            console.log(pkgid, " 渠道，传递指定消息gameClose");
            window.parent.postMessage("gameClose", '*');
            return true;
        }
        else if (pkgid == "ii_zb") {
            if (globalThis.closeIIGame) {
                globalThis.closeIIGame();
                return true;
            }
        }
        else if (yy.thirdPlatform.getPlatformName()) {
            // 【框架通用SDK处理方案】
            yy.thirdPlatform.exitGame();
            return true;
        }
        else if (urlParam && urlParam.return_url) {
            // return_url 改为通用方案
            console.debug(pkgid, "渠道, 触发退出游戏事件，return_url=", urlParam.return_url);
            location.href = urlParam.return_url;
            return true;
        }

        // 保底退出方案
        location.href = "android://close";
        setTimeout(() => { cc.game.end(); }, 0);
        return true;
    }

    // 当前是否在游戏中
    static get inGaming(): boolean {
        return yy.clientSite.getTableID() >= 0;
    }

    // 获取普通场可用房间
    static getUsefulRoomFlag(gameID: number): number {
        const gameInfo = yy.getGameInfo(gameID);
        if (!gameInfo || !gameInfo.rooms) return -1;
        let roomList: yy.IRoomServerInfo[] = [];
        gameInfo.rooms.forEach((e: yy.IRoomServerInfo) => {
            // 不展示好友房
            if (e.type == 7) return;
            roomList.push(e);
        });
        if (!roomList || !roomList.length) return -1;
        roomList.sort((a: yy.IRoomServerInfo, b: yy.IRoomServerInfo) => {
            if (a.isExerciseRoom()) return -1;
            else if (b.isExerciseRoom()) return 1;
            const isZegoA = a.name.search('Zego') >= 0;
            const isZegoB = b.name.search('Zego') >= 0;
            const i_a = a.getKeyInt("ShowKV_TitleIndex", -1);
            const i_b = b.getKeyInt("ShowKV_TitleIndex", -1);
            return isZegoA == isZegoB ? (i_a - i_b) : (isZegoA ? -1 : 1);
        });
        for (const info of roomList) {
            // 体验场
            if (info.isExerciseRoom())
                return info.flag;
            // 非token方式进入，屏蔽token房
            if (!GameConfig.isTokenRoom && info.type == 8) continue;
            const min = info.enterLimitMinCoin;
            const max = info.enterLimitMaxCoin;
            const money = yy.myself.getBodyMoney(info.playMoneyType);
            if ((min <= 0 || min <= money) && (max <= 0 || max >= money))
                return info.flag;
        }
        return 0;
    }

    /** 游戏场景名 */
    static get gameSceneName(): string {
        return !!GameConfig.isHalfViewMode ? "GameSceneHalf" : "GameScene";
    }

    /** zego的游戏模式 */
    static get zegoGameMode(): number {
        const def = 0;
        if (!GameConfig.isZEGO) return def;
        const evnCfg = yy.thirdPlatform.getEnvConfigs();
        if (!evnCfg || !evnCfg.zego) return def;
        const mode = evnCfg.zego.gameMode;
        DebugExt.log('当前zego的游戏模式：', mode);
        return mode;
    }
}
